﻿using System.Collections.Generic;
using System.Linq;

namespace AutomatedDecisionMaking.Class.Algorithms
{
    class CarefulChoiceAlgorithm
    {
        private readonly DecisionMatrix _mDecisionMatrix;   /// Macierz decyzji
        private double _mMaxValue;                          /// Wartośc odpowiadająca podjętej decyzji
        private string _mDecision;                          /// Podjęta decyzja
        private MaxiMaxAlgorithm _mMaxiMaxAlgorithm;        /// Algorytm MaxiMax
        private MiniMaxAlgorithm _mMiniMaxAlgorithm;        /// Algorytm MiniMax
        private List<double> _mOptimistDecision;            /// Decyzje optymisty
        private List<string> _mOptimistDecisionStr;         /// Decyzje optymisty
        private List<double> _mPessimistDecision;           /// Decyzje pesymisty
        private List<string> _mPessimistDecisionStr;        /// Decyzje pesymisty
        private List<double> _mWeights;                     /// Wagi dla poszczególnych decyzji
        private List<string> _mWeightedValuesStr;           /// Wartości ważone 

        /// <summary>
        /// Konstruktor algorytmu realizującego kryterium ostrożnego wyboru.
        /// </summary>
        /// <param name="decisionMatrix">Macierz decyzji wprowadzona porzez użytkownika</param>
        public CarefulChoiceAlgorithm(DecisionMatrix decisionMatrix)
        {
            _mWeights = new List<double>();
            
            _mDecisionMatrix = decisionMatrix;
        }

        /// <summary>
        /// Wagi dla decyzji jakie może podjąć użytkownik
        /// </summary>
        /// <param name="weights">Wagi poszczwgólnych decyzji</param>
        public void SetWeights(List<double> weights)
        {
            _mWeights = weights;
        }

        /// <summary>
        /// Uruchomienie algorytmu i rozwiązanie postawionego zadania
        /// </summary>
        public void CalculateSolution()
        {
            UpdateValues();
            var weightedValues = new List<double>();
            int decisionNo = _mDecisionMatrix.DecisionList.Count;

            for(int i=0; i<decisionNo; ++i)
            {
                string element = _mDecisionMatrix.DecisionList.ElementAt(i);
                double value = _mWeights[i]*_mOptimistDecision[i] + (1 - _mWeights[i])*_mPessimistDecision[i];
                weightedValues.Add(value);
                _mWeightedValuesStr.Add(element + " : maxWażone = " + value);
                _mOptimistDecisionStr.Add(element + " : max = " + _mOptimistDecision[i]);
                _mPessimistDecisionStr.Add(element + " : min = " + _mPessimistDecision[i]);
            }

            _mMaxValue = weightedValues.Max();
            _mDecision = _mDecisionMatrix.DecisionList.ElementAt(weightedValues.FindIndex(w => w == _mMaxValue));



        }

        /// <summary>
        /// Dostęp do decyzji podjętych przez optymistę
        /// </summary>
        /// <returns>Decyzje optymisty</returns>
        public List<double> GetOptimistDecision()
        {
            return _mOptimistDecision;
        }

        /// <summary>
        /// Dostęp do decyzji podjętych przez optymistę
        /// </summary>
        /// <returns>Decyzje optymisty</returns>
        public List<string> GetOptimistDecisionStr()
        {
            return _mOptimistDecisionStr;
        }

        /// <summary>
        /// Dostęp do decyzji podjętych przez pesymistę
        /// </summary>
        /// <returns>Decyzje pesymisty</returns>
        public List<double> GetPessimistDecision()
        {
            return _mPessimistDecision;
        }

        /// <summary>
        /// Dostęp do decyzji podjętych przez pesymistę
        /// </summary>
        /// <returns>Decyzje pesymisty</returns>
        public List<string> GetPessimistDecisionStr()
        {
            return _mPessimistDecisionStr;
        }

        /// <summary>
        /// Dostę do wag dla poszczególnych decyzji
        /// </summary>
        /// <returns>Wagi dla decyzji</returns>
        public List<double> GetWeights()
        {
            return _mWeights;
        }

        /// <summary>
        /// Wartości ważone
        /// </summary>
        /// <returns>Wartości ważone</returns>
        public List<string> GetWeightedValuesStr()
        {
            return _mWeightedValuesStr;
        }

        /// <summary>
        /// Wartości odpowiadająca podjętej decyzji
        /// </summary>
        /// <returns>Wartość dla podjetej decyzji</returns>
        public double GetMaxValue()
        {
            return _mMaxValue;
        }

        /// <summary>
        /// Podjęta decyzja
        /// </summary>
        /// <returns>Podjęta decyzja</returns>
        public string GetDecision()
        {
            return _mDecision;
        }

        /// <summary>
        /// Aktualizacja danych dla algorytmu
        /// </summary>
        private void UpdateValues()
        {
            _mWeightedValuesStr = new List<string>();
            _mOptimistDecisionStr = new List<string>();
            _mPessimistDecisionStr = new List<string>();

            _mMaxiMaxAlgorithm = new MaxiMaxAlgorithm(_mDecisionMatrix);
            _mMaxiMaxAlgorithm.CalculateSolution();
            _mOptimistDecision = _mMaxiMaxAlgorithm.GetMaxValues();

            _mMiniMaxAlgorithm = new MiniMaxAlgorithm(_mDecisionMatrix);
            _mMiniMaxAlgorithm.CalculateSolution();
            _mPessimistDecision = _mMiniMaxAlgorithm.GetMinValues();
        }
    }
}
